import React, { FC, useCallback, useEffect, useRef } from 'react'
import { initViewer } from './viewer'
import css from './runtime.less'
import Viewer from 'bpmn-js/lib/Viewer'
import { diagram } from './diagram'
import { fitViewport } from './utils'

export default function ({ env, data, outputs, inputs }) {
  const containerRef = useRef(null)
  const viewRef = useRef<Viewer<null> | null>(null)
  const heighLightRef = useRef<string[]>(['Activity_0v7fc3e'])
  const diagramData = useRef<string>(diagram)
  const renderRef = useRef<(() => void) | null>(null)
  const render = () => {
    const container: HTMLElement = containerRef.current!
    if (!container) return () => {}
    let working = true
    let view: any = null
    initViewer(container, diagramData.current)
      .then((view) => {
        if (!working) {
          view?.destroy?.()
          return
        }
        fitViewport(view.get('canvas'))
        viewRef.current = view
        setNodeStyle()
        return view
      })
      .catch((err: any) => {
        console.log(err)
      })
      .finally(() => {
        container.querySelector('.bjs-powered-by')?.remove?.()
      })
    return () => {
      working = false
      view?.destroy?.()
      view = null
    }
  }

  const setNodeStyle = () => {
    const container: HTMLElement = containerRef.current!
    let heighLightList: string[] = heighLightRef.current!
    const isHeighLight = (id: string | null) => {
      return heighLightList?.some?.((i) => i == id) ?? false
    }
    const { normalColor, normalBorder, normalBack, heighLightColor, heighLightBorder, heighLightBack } = data
    container.querySelectorAll('.djs-group [data-element-id]').forEach((elt) => {
      const id = elt.getAttribute('data-element-id')
      const rects = elt.querySelectorAll('.djs-visual rect, .djs-visual circle') as NodeListOf<HTMLElement>
      const texts = elt.querySelectorAll('.djs-visual text') as NodeListOf<HTMLElement>
      let color = normalColor
      let border = normalBorder
      let back = normalBack
      if (isHeighLight(id)) {
        color = heighLightColor
        border = heighLightBorder
        back = heighLightBack
      }
      rects.forEach((rect) => {
        rect.style.stroke = border
        rect.style.fill = back
      })
      texts.forEach((text) => {
        text.style.fill = color
      })
    })
  }

  useEffect(() => {
    setNodeStyle()
  }, [data.normalColor, data.normalBorder, data.normalBack, data.heighLightColor, data.heighLightBorder, data.heighLightBack])

  useEffect(() => {
    viewRef.current && fitViewport(viewRef.current.get('canvas'))
  }, [data.style, data.style?.width, data.style?.height])

  useEffect(() => {
    renderRef.current = render()
    return () => {
      renderRef.current?.()
      renderRef.current = null
    }
  }, [containerRef.current])

  inputs['setDiagramXml']?.((val: string, outputRels: any) => {
    diagramData.current = val
    renderRef.current?.()
    renderRef.current = render()
    outputRels?.['onSetDiagramXmlFinish']?.(val)
  })

  inputs['setHeighLightList']?.((val: string[], outputRels: any) => {
    heighLightRef.current = val
    setNodeStyle()
    outputRels?.['onSetHeighLightListFinish']?.(val)
  })
  return <div className={css['container']} ref={containerRef}></div>
}
